/**
 * @file 通知化装饰器
 * @author DuskyHuang 圣子
*/

import { swapper } from "./swapper";
import { notifier } from '../../core/boot';

/** 发送通知方法装饰器 */
export const notify: (type: string | number, ...args: any[]) => MethodDecorator
    // DecoratorFactory < MethodDecorator, [ string | number, ...any[]] >
    =
    swapper<MethodDecorator>(([, , descriptor]: Parameters<MethodDecorator>, type: string | number, ...args: any[]) => {
        const method = descriptor.value as Handler;
        return {
            ...descriptor,
            value: function (...params: any[]) {
                const res = Function.invoke(method, this, ...params);
                notifier.dispatch(type, ...args);
                return res;
            }
        }
    });

/** 监听通知方法装饰器 */
export const on: (type: string | number, priority?: number) => MethodDecorator
    // DecoratorFactory<MethodDecorator, [ string | number,  number?]>
    =
    swapper<MethodDecorator>(([target, , descriptor]: Parameters<MethodDecorator>, type: string | number, priority?: number) => {
        const method = descriptor.value as Handler;
        notifier.attach(type, method, target, false, priority);
        return descriptor;
    });


/** 监听通知方法装饰器 */
export const once: (type: string | number, priority?: number) => MethodDecorator
    // DecoratorFactory<MethodDecorator, [ string | number,  number?]>
    =
    swapper<MethodDecorator>(([target, , descriptor]: Parameters<MethodDecorator>, type: string | number, priority?: number) => {
        const method = descriptor.value as Handler;
        notifier.attach(type, method, target, true, priority);
        return descriptor;
    });

/** 条件触发方法装饰器 */
export const when: (type: string | number, condition: boolean | ((this: void) => boolean), priority?: number) => MethodDecorator =
    // DecoratorFactory<MethodDecorator, [ string | number,  boolean | ((this: void) => boolean),  number?]>
    swapper<MethodDecorator>(([target, , descriptor]: Parameters<MethodDecorator>, type: string | number, condition?: boolean | Validator, priority?: number) => {
        const method = descriptor.value as Handler;
        const decorated: PropertyDescriptor = {
            ...descriptor,
            value(...params: any[]) {
                if (isFunc(condition) && Function.invoke(condition, this) || isBool(condition) && condition) {
                    return Function.invoke(method, this, ...params);
                }
            }
        }
        notifier.attach(type, decorated.value, target, false, priority);
        return decorated;
    });

/** 卸载通知方法装饰器 */
export const off: (type: string | number) => MethodDecorator
    // DecoratorFactory<MethodDecorator, [ string | number]>
    =
    swapper<MethodDecorator>(([target, , descriptor]: Parameters<MethodDecorator>, type: string | number) => {
        const method = descriptor.value as Handler;
        notifier.detach(type, method, target);
        return descriptor;
    });